package com.atguigu.webflux.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.reactive.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.security.authentication.UserDetailsRepositoryReactiveAuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.core.userdetails.MapReactiveUserDetailsService;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.authentication.RedirectServerAuthenticationSuccessHandler;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsConfigurationSource;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;

import java.util.Collections;

import static org.springframework.security.config.Customizer.withDefaults;

@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {
  @Autowired
  private final ReactiveUserDetailsService bizReactiveUserDetailsService;

  public SecurityConfig(ReactiveUserDetailsService bizReactiveUserDetailsService) {
    this.bizReactiveUserDetailsService = bizReactiveUserDetailsService;
  }

  @Primary
  @Bean
  PasswordEncoder passwordEncoder() {
    return PasswordEncoderFactories.createDelegatingPasswordEncoder();
  }

  @Bean
  public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
    // 1、定义哪些请求需要认证，哪些不需要
    http.authorizeExchange(exchanges -> {
      // 1.1、允许所有人都访问静态资源；
      exchanges.matchers(PathRequest.toStaticResources()
          .atCommonLocations()).permitAll();

      exchanges
          .pathMatchers("/signon", "/signup", "/cgi-bin/signup", "/cgi-bin/login.pl", "/static/**", "/css/**", "/js/**")
          .permitAll();

      // 1.2、剩下的所有请求都需要认证（登录）
      // TODO: 当前放行了所有用户请求，需要后续需要开启
      exchanges.anyExchange().authenticated();
    }).formLogin(formLoginSpec -> {
      // 2、开启默认的表单登录
      formLoginSpec// 指定自定义登录页面
          .loginPage("/signon").authenticationSuccessHandler(new RedirectServerAuthenticationSuccessHandler("/home"));
      // 登录处理URL，默认是/login
      // .loginProcessingUrl("/login")
      // 登录成功后的默认跳转页面
      // .defaultSuccessUrl("/")
      // 登录失败后跳转页面
      // .failureUrl("/signon?error=true");
    }).logout(logoutSpec -> {
      logoutSpec.logoutUrl("/signoff");
    });
    //
    // 3、安全控制:
    http.csrf(ServerHttpSecurity.CsrfSpec::disable).cors(cors -> cors.configurationSource(corsConfigurationSource())); // Enable
                                                                                                                       // and
                                                                                                                       // configure
                                                                                                                       // CORS;
    // 目前认证： 用户名 是 user 密码是默认生成。
    // 期望认证： 去数据库查用户名和密码

    // 4、配置 认证规则： 如何去数据库中查询到用户;
    // Spring Security 底层使用 ReactiveAuthenticationManager 去查询用户信息
    // ReactiveAuthenticationManager 有一个实现是
    // UserDetailsRepositoryReactiveAuthenticationManager： 用户信息去数据库中查
    // UDRespAM 需要 ReactiveUserDetailsService：
    // 我们只需要自己写一个 ReactiveUserDetailsService： 响应式的用户详情查询服务
    http.authenticationManager(
        new UserDetailsRepositoryReactiveAuthenticationManager(
            bizReactiveUserDetailsService));

    // http.addFilterAt();
    return http.build();
  }

  @Bean
  public CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(Collections.singletonList("*")); // Allow all origins, including 'null'
    configuration.addAllowedOrigin("null"); // Explicitly allow 'null' origin
    configuration.setAllowedMethods(Collections.singletonList("*")); // Allow all HTTP methods
    configuration.setAllowedHeaders(Collections.singletonList("*")); // Allow all headers
    configuration.setAllowCredentials(false); // Disable credentials for simplicity

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration); // Apply to all paths
    return source;
  }
}
